#******************************************************************
#
# Copyright 2016 Samsung Electronics All Rights Reserved.
#
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Import('env')
import SCons.Errors
import SCons.Util
import os
import sys
import re
import subprocess
from shutil import copyfile

target_os = env.get('TARGET_OS')
src_dir = env.get('SRC_DIR')
build_dir = env.get('BUILD_DIR')
mbedtls_dir = os.path.join(src_dir, 'extlibs', 'mbedtls', 'mbedtls')
start_dir = os.getcwd()
mbedtls_config_file = 'config-iotivity.h' if target_os != 'windows' else 'config-iotivity_windows.h'

# The mbedtls_revision tag here must match the one in extlibs/mbedtls/prep.sh.
mbedtls_revision = 'mbedtls-2.4.2'
if not os.path.exists(mbedtls_dir):
    msg = '''
*********************************** Error: ************************************
* The iotivity repository does not include cryptgraphic software,
* but requires it to be added by the developer.
* Please download mbedtls using the following command:
* $ git clone https://github.com/ARMmbed/mbedtls.git extlibs/mbedtls/mbedtls -b %s
*******************************************************************************
''' % mbedtls_revision
    Exit(msg)

os.chdir(mbedtls_dir)

# Right now this script assumes the revision is a tag, and not a branch or
# an arbitrary commit. If this changes, update the check below, or else
# the script will always conclude the repo is not up to date because a tag
# with that name doesn't exist.
# Tizen uses its own process to prepare the mbedTLS repo in gbsbuild.sh.
if os.path.exists('.git/HEAD'):
    out = subprocess.check_output('git tag -l ' + mbedtls_revision, shell=True).rstrip()
    if mbedtls_revision not in SCons.Util.to_String(out):
        msg = '''
*********************************** Error: ************************************
* Your mbedTLS repo is not up to date with the version required by iotivity.
* Please update with the following commands:
*     $ cd extlibs/mbedtls/mbedtls
*     $ git fetch
*******************************************************************************
'''
        Exit(msg)

found = False

# Check for the desired version of mbedTLS, first.
pattern = '#define MBEDTLS_VERSION_NUMBER         0x02040200'
mbedtls_header = os.path.join('include', 'mbedtls', 'version.h')
with open(mbedtls_header, 'r') as stream:
    for line in stream:
        if pattern in line:
            found = True
            break

# If we're on the right version, check for the patch being applied.
if found:
    found = False
    pattern = '#if defined(MBEDTLS_HAVE_WINSOCK2)'
    mbedtls_header = os.path.join('include', 'mbedtls', 'net_sockets.h')
    with open(mbedtls_header, 'r') as stream:
        for line in stream:
            if pattern in line:
                found = True
                break

# If either is not the case, reset and apply the patch.
if not found:
    if os.path.exists('.git/HEAD'):
        # Apply ocf patch on git revision
        print("Syncing/patching mbedtls external project...")
        cmd = 'git checkout -f development && git reset --hard ' + mbedtls_revision + ' && git clean -f && git apply --whitespace=fix ../ocf.patch'
    else:
        # Fallback to regular patch command
        cmd = 'patch -p1 -l -f < ../ocf.patch'

    try:
        retcode = subprocess.call(cmd, shell=True)
        if retcode:
            Exit("mbedtls: sync failed: " + str(retcode))
    except OSError as e:
        Exit("mbedtls: execution failed: " + e)

os.chdir(start_dir)

# Copy IoTivity's version of the mbedtls build configuration file
# from extlibs/mbedtls/iotivity-config.h
# to extlibs/mbedtls/mbedtls/include/mbedtls/config.h
iotivity_config = os.path.join(src_dir, 'extlibs', 'mbedtls', mbedtls_config_file)
mbedtls_config = os.path.join(src_dir, 'extlibs', 'mbedtls', 'mbedtls',
                              'include', 'mbedtls', 'config.h')

try:
    copyfile(iotivity_config, mbedtls_config)
except:
    msg = 'mbedtls SConscript: cannot copy ' + iotivity_config + ' to ' + mbedtls_config
    msg += 'error: ' + str(sys.exc_info()[0])
    Exit(msg)
else:
    print('Copied IoTivity version of config.h to ' + mbedtls_config)

mbedtls_env = env.Clone()

mbedtls_env.AppendUnique(CPPPATH=[
    mbedtls_dir,
    os.path.join(mbedtls_dir, 'include'),
    os.path.join(mbedtls_dir, 'include', 'mbedtls')
])
if 'g++' in mbedtls_env.get('CXX'):
    mbedtls_env.AppendUnique(CFLAGS=['-Wall'])

    if mbedtls_env['CC'] != 'cl':
        mbedtls_env.AppendUnique(CFLAGS=['-fPIC'])

######################################################################
# Source files and Target(s)
######################################################################
mbedtls_src = [
    'mbedtls/library/debug.c',
    'mbedtls/library/net_sockets.c',
    'mbedtls/library/ssl_cache.c',
    'mbedtls/library/ssl_ciphersuites.c',
    'mbedtls/library/ssl_cli.c',
    'mbedtls/library/ssl_cookie.c',
    'mbedtls/library/ssl_srv.c',
    'mbedtls/library/ssl_ticket.c',
    'mbedtls/library/ssl_tls.c'
]

mbedcrypto_src = [
    'mbedtls/library/aes.c',
    'mbedtls/library/aesni.c',
    'mbedtls/library/arc4.c',
    'mbedtls/library/asn1parse.c',
    'mbedtls/library/asn1write.c',
    'mbedtls/library/base64.c',
    'mbedtls/library/bignum.c',
    'mbedtls/library/blowfish.c',
    'mbedtls/library/camellia.c',
    'mbedtls/library/ccm.c',
    'mbedtls/library/cipher.c',
    'mbedtls/library/cipher_wrap.c',
    'mbedtls/library/ctr_drbg.c',
    'mbedtls/library/des.c',
    'mbedtls/library/dhm.c',
    'mbedtls/library/ecdh.c',
    'mbedtls/library/ecdsa.c',
    'mbedtls/library/ecjpake.c',
    'mbedtls/library/ecp.c',
    'mbedtls/library/ecp_curves.c',
    'mbedtls/library/entropy.c',
    'mbedtls/library/entropy_poll.c',
    'mbedtls/library/error.c',
    'mbedtls/library/gcm.c',
    'mbedtls/library/havege.c',
    'mbedtls/library/hmac_drbg.c',
    'mbedtls/library/md.c',
    'mbedtls/library/md2.c',
    'mbedtls/library/md4.c',
    'mbedtls/library/md5.c',
    'mbedtls/library/md_wrap.c',
    'mbedtls/library/memory_buffer_alloc.c',
    'mbedtls/library/oid.c',
    'mbedtls/library/padlock.c',
    'mbedtls/library/pem.c',
    'mbedtls/library/pk.c',
    'mbedtls/library/pk_wrap.c',
    'mbedtls/library/pkcs12.c',
    'mbedtls/library/pkcs5.c',
    'mbedtls/library/pkparse.c',
    'mbedtls/library/pkwrite.c',
    'mbedtls/library/platform.c',
    'mbedtls/library/ripemd160.c',
    'mbedtls/library/rsa.c',
    'mbedtls/library/sha1.c',
    'mbedtls/library/sha256.c',
    'mbedtls/library/sha512.c',
    'mbedtls/library/threading.c',
    'mbedtls/library/timing.c',
    'mbedtls/library/version.c',
    'mbedtls/library/version_features.c',
    'mbedtls/library/xtea.c'
]

mbeX509_src = [
    'mbedtls/library/certs.c',
    'mbedtls/library/pkcs11.c',
    'mbedtls/library/x509.c',
    'mbedtls/library/x509_create.c',
    'mbedtls/library/x509_crl.c',
    'mbedtls/library/x509_crt.c',
    'mbedtls/library/x509_csr.c',
    'mbedtls/library/x509write_crt.c',
    'mbedtls/library/x509write_csr.c'
]

mbedcrypto_env = mbedtls_env.Clone()
static_libmbedcrypto = mbedcrypto_env.StaticLibrary(build_dir + 'mbedcrypto', mbedcrypto_src)
mbedcrypto_env.UserInstallTargetLib(static_libmbedcrypto, 'mbedcrypto')

mbex509_env = mbedtls_env.Clone()
mbex509_env.AppendUnique(LIBS=['mbedcrypto'])
static_libmbedx509 = mbex509_env.StaticLibrary(build_dir + 'mbedx509', mbeX509_src)
mbex509_env.UserInstallTargetLib(static_libmbedx509, 'mbedx509')

mbedtls_env.AppendUnique(LIBS=['mbedx509', 'mbedcrypto'])
static_libmbedtls = mbedtls_env.StaticLibrary(build_dir + 'mbedtls', mbedtls_src)
mbedtls_env.UserInstallTargetLib(static_libmbedtls, 'mbedtls')
